package com.why.cachecloud.client.redis.cachecloud.client.lettuce.util.util.impl;

import com.why.cachecloud.client.redis.cachecloud.client.lettuce.util.util.RedisUtil;
import io.lettuce.core.*;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author why
 * @Version 1.0.0
 * @Since 1.0
 * @Date 2022/8/30
 */
public class LettuceSentinelUtil<T> implements RedisUtil<T> {
    private Logger log = LoggerFactory.getLogger(getClass());
    @Setter
    private StatefulRedisConnection<String, T> connection;
    private RedisCommands<String, T> commands;

    @PostConstruct
    public void inti() {
        commands = connection.sync();
    }

    @Override
    public void set(String key, T value) {
        commands.set(key, value);
    }

    @Override
    public void set(String key, T value, long seconds) {
        commands.setex(key, seconds, value);
    }

    @Override
    public T get(String key) {
        return commands.get(key);
    }

    @Override
    public void del(String key) {
        commands.del(key);
    }

    @Override
    public void del(String... keys) {
        commands.del(keys);
    }

    @Override
    public long strLen(String key) {
        return commands.strlen(key);
    }

    @Override
    public long incr(String key) {
        return commands.incr(key);
    }

    @Override
    public long decr(String key) {
        return commands.decr(key);
    }

    @Override
    public long incrBy(String key, long increment) {
        return commands.incrby(key, increment);
    }

    @Override
    public boolean setNx(String key, T value) {
        return commands.setnx(key, value);
    }

    @Override
    public T getSet(String key, T value) {
        return commands.getset(key, value);
    }

    @Override
    public Boolean expire(String key, long seconds) {
        return commands.expire(key, seconds);
    }

    @Override
    public Boolean expireAt(String key, Date date) {
        return null;
    }


    @Override
    public void geoAdd(String key, double longitude, double latitude, T member) {
        Long result = commands.geoadd(key, longitude, latitude, member);
        log.info("geoadd command result:{}", result);
    }

    @Override
    public List<GeoCoordinates> geoPos(String key, T... members) {
        List<GeoCoordinates> list = commands.geopos(key, members);
        return list;
    }

    @Override
    public Double geoDist(String key, T source, T dest) {
        Double geodist = commands.geodist(key, source, dest, GeoArgs.Unit.km);
        return geodist;
    }

    @Override
    public Set<T> geoRadius(String key, double longitude, double latitude, double radius) {
        Set<T> geoRadius = commands.georadius(key, longitude, latitude, radius, GeoArgs.Unit.km);
        return geoRadius;
    }

    @Override
    public Set<T> geoRadiusByMember(String key, double radius, T member) {
        Set<T> set = commands.georadiusbymember(key, member, radius, GeoArgs.Unit.km);
        return set;
    }

    // GEO END
    @Override
    public void rPush(String key, T... values) {
        Long result = commands.rpush(key, values);
        log.info("lpush command result:{}", result);
    }

    @Override
    public void lPush(String key, T... values) {
        Long result = commands.lpush(key, values);
        log.info("lpush command result:{}", result);
    }

    @Override
    public void lInsert(String key, boolean before, T pivot, T insertValue) {
        commands.linsert(key, before, pivot, insertValue);
    }

    @Override
    public List<T> lRange(String key, int start, int end) {
        return commands.lrange(key, start, end);
    }

    @Override
    public T lIndex(String key, long index) {
        return commands.lindex(key, index);
    }

    @Override
    public Long lLen(String key) {
        return commands.llen(key);
    }

    @Override
    public T lPop(String key) {
        return commands.lpop(key);
    }

    @Override
    public T rPop(String key) {
        return commands.rpop(key);
    }

    @Override
    public void lRem(String key, long count, T value) {
        Long result = commands.lrem(key, count, value);
        log.info("lrem command result :{}", result);
    }

    @Override
    public void lTrim(String key, long start, long end) {
        String result = commands.ltrim(key, start, end);
        log.info("ltrim result:{}", result);
    }

    @Override
    public void lSet(String key, long index, T value) {
        String result = commands.lset(key, index, value);
        log.info("lset command result:{}", result);
    }

    @Override
    public T blPop(String key, long timeout) {
        KeyValue<String, T> blpop = commands.blpop(timeout, key);
        return blpop.getValue();
    }

    @Override
    public T brPop(String key, long timeout) {
        KeyValue<String, T> blpop = commands.brpop(timeout, key);
        return blpop.getValue();
    }

    // list end
    @Override
    public void hSet(String key, String field, T value) {
        Boolean result = commands.hset(key, field, value);
        log.info("hSet command result:{}", result);
    }

    @Override
    public T hGet(String key, String field) {
        return commands.hget(key, field);
    }

    @Override
    public void hDel(String key, String... fields) {
        Long result = commands.hdel(key, fields);
        log.info("hDel command result:{}", result);
    }

    @Override
    public long hLen(String key) {
        return commands.hlen(key);
    }

    @Override
    public Map<String, T> hGetAll(String key) {
        Map<String, T> map = commands.hgetall(key);
        return map;
    }

    @Override
    public Map<String, T> hmGet(String key, String... fields) {
        List<KeyValue<String, T>> list = commands.hmget(key, fields);
        Map<String, T> map = list.stream().collect(Collectors.toMap(KeyValue::getKey, KeyValue::getValue, (k1, k2) -> k2));
        return map;
    }

    @Override
    public void hmSet(String key, Map<String, T> kvs) {
        commands.hmset(key, kvs);
    }

    @Override
    public boolean hExists(String key, String field) {
        return commands.hexists(key, field);
    }

    @Override
    public List<String> hKeys(String key) {
        return commands.hkeys(key);
    }

    @Override
    public List<T> hVals(String key) {
        return commands.hvals(key);
    }

    @Override
    public Boolean hSetNx(String key, String field, T value) {
        Boolean result = commands.hsetnx(key, field, value);
        log.info("hsetnx command result:{}", result);
        return result;
    }

    @Override
    public void hIncrBy(String key, String field, long increment) {
        Long result = commands.hincrby(key, field, increment);
        log.info("hincrby command result:{}", result);
    }

    @Override
    public void hIncrByFloat(String key, String field, double increment) {
        Double result = commands.hincrbyfloat(key, field, increment);
        log.info("hincrbyfloat command result:{}", result);
    }

    @Override
    public long hStrLen(String key, String field) {
        return commands.hstrlen(key, field);
    }

    // hash end
    @Override
    public void sAdd(String key, T... elements) {
        Long result = commands.sadd(key, elements);
        log.info("sadd command result:{}", result);
    }

    @Override
    public void sRem(String key, T... elements) {
        Long result = commands.srem(key, elements);
        log.info("srem command result:{}", result);
    }

    @Override
    public long sCard(String key) {
        return commands.scard(key);
    }

    @Override
    public boolean sIsMember(String key, T element) {
        return commands.sismember(key, element);
    }

    @Override
    public T sPop(String key) {
        return commands.spop(key);
    }

    @Override
    public Set<T> sMembers(String key) {
        return commands.smembers(key);
    }

    @Override
    public Set<T> sInter(String key1, String key2) {
        return commands.sinter(key1, key2);
    }

    @Override
    public Set<T> sUnion(String key1, String key2) {
        return commands.sunion(key1, key2);
    }

    @Override
    public Set<T> sDiff(String key1, String key2) {
        return commands.sdiff(key1, key2);
    }

    /**
     * 将一个或多个 member 元素及其 score 值加入到有序集 key 当中
     *
     * @param key
     * @param elements
     */
    @Override
    public void zAdd(String key, Map<T, Double> elements) {
        ScoredValue[] arr = new ScoredValue[elements.size()];
        final int[] index = {0};
        elements.forEach((k, v) -> {
            ScoredValue<T> scoredValue = ScoredValue.fromNullable(v, k);
            arr[index[0]] = scoredValue;
            index[0]++;
        });
        if (arr.length == 0) {
            return;
        }
        Long result = commands.zadd(key, arr);
        log.info("zadd command result:{}", result);
    }

    @Override
    public void zAdd(String key, T member, Double socre) {
        Long result = commands.zadd(key, socre, member);
        log.info("zadd single command result:{}", result);
    }

    /**
     * 返回集合 key 中元素的数量
     *
     * @param key
     * @return
     */
    @Override
    public long zCard(String key) {
        return commands.zcard(key);
    }

    /**
     * 返回有序集 key 中， score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量
     *
     * @param key
     * @param minScore
     * @param maxScore
     * @return
     */
    @Override
    public Long zCount(String key, double minScore, double maxScore) {
        return commands.zcount(key, Range.create(minScore, maxScore));
    }

    /**
     * 为有序集 key 的成员 member 的 score 值加上增量 increment
     *
     * @param key
     * @param member
     * @param increment
     * @return
     */
    @Override
    public Double zIncrBy(String key, T member, double increment) {
        return commands.zincrby(key, increment, member);
    }

    /**
     * 计算给定的一个或多个有序集的并集
     *
     * @param destKey
     * @param keys
     */
    @Override
    public void zInterStore(String destKey, String... keys) {
        commands.zinterstore(destKey, keys);
    }

    /**
     * 并集
     *
     * @param destKey
     * @param keys
     */
    @Override
    public void zUnionStore(String destKey, String... keys) {
        commands.zunionstore(destKey, keys);
    }

    /**
     * 返回有序集 key 中，指定下标区间 [start, stop] 内的元素。其中成员的位置按 score 值递增(从小到大)来排序
     * 按照索引位置返回信息
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    @Override
    public List<T> zRange(String key, long start, long end) {
        List<T> list = commands.zrange(key, start, end);
        return list;
    }

    /**
     * 返回有序集 key 中，指定下标区间 [start, stop] 内的元素。其中成员的位置按 score 值递增(从大到小)来排序
     * 按照索引位置返回信息
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    @Override
    public List<T> zRevRange(String key, long start, long end) {
        return commands.zrevrange(key, start, end);
    }

    /**
     * 返回有序集 key 中，所有 score 值介于 [min, max] 之间的成员有序集成员按 score 值递增(从小到大)次序排列
     * 按照score
     *
     * @param key
     * @param minScore
     * @param maxScore
     * @return
     */
    @Override
    public List<T> zRangeByScore(String key, double minScore, double maxScore) {
        return commands.zrangebyscore(key, Range.create(minScore, maxScore));
    }

    /**
     * 返回有序集 key 中，所有 score 值介于 [min, max] 之间的成员有序集成员按 score 值递增(从大到小)次序排列
     * 按照score
     *
     * @param key
     * @param minScore
     * @param maxScore
     * @return
     */
    @Override
    public List<T> zRevRangeByScore(String key, double minScore, double maxScore) {
        return commands.zrevrangebyscore(key, Range.create(minScore, maxScore));
    }

    /**
     * 返回有序集 key 中元素的排名 rank。其中有序集成员按 score 值递增(从小到大)顺序排列
     *
     * @param key
     * @param member
     * @return
     */
    @Override
    public long zRank(String key, T member) {
        return commands.zrank(key, member);
    }

    /**
     * 返回有序集 key 中元素的排名 rank。其中有序集成员按 score 值递增(从大到小)顺序排列
     *
     * @param key
     * @param member
     * @return
     */
    @Override
    public long zRevRank(String key, T member) {
        return commands.zrevrank(key, member);
    }

    /**
     * 移除有序集 key 中的一个或多个成员，不存在的成员将被忽略
     *
     * @param key
     * @param members
     * @return
     */
    @Override
    public Long zRem(String key, T... members) {
        return commands.zrem(key, members);
    }

    /**
     * 移除有序集 key 中，指定下标排名(rank)区间 [start, stop] 内的所有成员
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    @Override
    public long zRemRangeByRank(String key, long start, long end) {
        return commands.zremrangebyrank(key, start, end);
    }

    /**
     * 移除有序集 key 中，所有 score 值介于 [minScore, maxScore] 之间
     *
     * @param key
     * @param minScore
     * @param maxScore
     * @return
     */
    @Override
    public long zRemRangeByScore(String key, double minScore, double maxScore) {
        return commands.zremrangebyscore(key, Range.create(minScore, maxScore));
    }

    /**
     * 返回有序集 key 中，成员 member 的 score 值
     *
     * @param key
     * @param member
     * @return
     */
    @Override
    public Double zScore(String key, T member) {
        return commands.zscore(key, member);
    }
    // zset end

    /**
     * 命令将所有元素参数添加到 HyperLogLog 数据结构
     *
     * @param key
     * @param elements
     */
    @Override
    public void pfAdd(String key, T... elements) {
        commands.pfadd(key, elements);
    }

    /**
     * 命令返回给定 HyperLogLog 的基数估算值
     *
     * @param key
     * @return
     */
    @Override
    public long pfCount(String key) {
        return commands.pfcount(key);
    }

    /**
     * 命令将多个 HyperLogLog 合并为一个 HyperLogLog ，合并后的 HyperLogLog 的基数估算值是通过对所有 给定 HyperLogLog 进行并集计算得出
     *
     * @param destKey
     * @param sourceKeys
     */
    @Override
    public void pfMerge(String destKey, String... sourceKeys) {
        commands.pfmerge(destKey, sourceKeys);
    }
}
